/*****************************************************************************
 *                                McPAT
 *                      SOFTWARE LICENSE AGREEMENT
 *            Copyright 2012 Hewlett-Packard Development Company, L.P.
 *                          All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.”
 *
 ***************************************************************************/
/********************************************************************
 *      Modified by:
 * Jingwen Leng, University of Texas, Austin
 * Syed Gilani, University of Wisconsin–Madison
 * Tayler Hetherington, University of British Columbia
 * Ahmed ElTantawy, University of British Columbia
 * Vijay Kandiah, Northwestern University
 ********************************************************************/

#include "processor.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <fstream>
#include <iostream>
#include "XML_Parse.h"
#include "array.h"
#include "cacti/basic_circuit.h"
#include "const.h"
#include "parameter.h"
#include "version.h"

Processor::Processor(ParseXML *XML_interface)
    : XML(XML_interface),  // TODO: using one global copy may have problems.
      mc(0),
      niu(0),
      pcie(0),
      flashcontroller(0) {
  /*
   *  placement and routing overhead is 10%, core scales worse than cache 40% is
   * accumulated from 90 to 22nm There is no point to have heterogeneous memory
   * controller on chip, thus McPAT only support homogeneous memory controllers.
   */
  rt_power.reset();
  int i;
  double pppm_t[4] = {1, 1, 1, 1};
  l2_power = 0;
  idle_core_power = 0;
  set_proc_param();
  if (procdynp.homoCore)
    numCore = procdynp.numCore == 0 ? 0 : 1;
  else
    numCore = procdynp.numCore;

  if (procdynp.homoL2)
    numL2 = procdynp.numL2 == 0 ? 0 : 1;
  else
    numL2 = procdynp.numL2;

  if (XML->sys.Private_L2 && numCore != numL2) {
    cout << "Number of private L2 does not match number of cores" << endl;
    exit(0);
  }

  if (procdynp.homoL3)
    numL3 = procdynp.numL3 == 0 ? 0 : 1;
  else
    numL3 = procdynp.numL3;

  if (procdynp.homoNOC)
    numNOC = procdynp.numNOC == 0 ? 0 : 1;
  else
    numNOC = procdynp.numNOC;

  //  if (!procdynp.homoNOC)
  //  {
  //	  cout<<"Current McPAT does not support heterogeneous NOC"<<endl;
  //      exit(0);
  //  }

  if (procdynp.homoL1Dir)
    numL1Dir = procdynp.numL1Dir == 0 ? 0 : 1;
  else
    numL1Dir = procdynp.numL1Dir;

  if (procdynp.homoL2Dir)
    numL2Dir = procdynp.numL2Dir == 0 ? 0 : 1;
  else
    numL2Dir = procdynp.numL2Dir;

  for (i = 0; i < numCore; i++) {
    cores.push_back(new Core(XML, i, &interface_ip));
    cores[i]->computeEnergy();
    cores[i]->computeEnergy(false);
    if (procdynp.homoCore) {
      core.area.set_area(core.area.get_area() +
                         cores[i]->area.get_area() * procdynp.numCore);
      set_pppm(pppm_t, cores[i]->clockRate * procdynp.numCore, procdynp.numCore,
               procdynp.numCore, procdynp.numCore);
      // set the exClockRate
      exClockRate = cores[0]->clockRate;  // TODO; get from XML file
      // cout<<"****EX clock rate:"<<exClockRate<<endl;
      core.power = core.power + cores[i]->power * pppm_t;
      set_pppm(pppm_t, 1 / cores[i]->executionTime, procdynp.numCore,
               procdynp.numCore, procdynp.numCore);
      core.rt_power = core.rt_power + cores[i]->rt_power * pppm_t;
      area.set_area(
          area.get_area() +
          core.area.get_area());  // placement and routing overhead is
                                  // 10%, core scales worse than cache
                                  // 40% is accumulated from 90 to 22nm
      power = power + core.power;
      rt_power = rt_power + core.rt_power;
    } else {
      core.area.set_area(core.area.get_area() + cores[i]->area.get_area());
      area.set_area(
          area.get_area() +
          cores[i]->area.get_area());  // placement and routing overhead is 10%,
                                       // core scales worse than cache 40% is
                                       // accumulated from 90 to 22nm

      set_pppm(pppm_t, cores[i]->clockRate, 1, 1, 1);
      // set the exClockRate
      exClockRate = cores[0]->clockRate;  // TODO; get from XML file
      // cout<<"****EX clock rate:"<<exClockRate<<endl;
      core.power = core.power + cores[i]->power * pppm_t;
      power = power + cores[i]->power * pppm_t;

      set_pppm(pppm_t, 1 / cores[i]->executionTime, 1, 1, 1);
      core.rt_power = core.rt_power + cores[i]->rt_power * pppm_t;
      rt_power = rt_power + cores[i]->rt_power * pppm_t;
    }
  }

  if (!XML->sys.Private_L2) {
    if (numL2 > 0)
      for (i = 0; i < numL2; i++) {
        l2array.push_back(new SharedCache(XML, i, &interface_ip));

        l2array[i]->computeEnergy();
        l2array[i]->computeEnergy(false);
        if (procdynp.homoL2) {
          l2.area.set_area(l2.area.get_area() +
                           l2array[i]->area.get_area() * procdynp.numL2);
          set_pppm(pppm_t, l2array[i]->cachep.clockRate * procdynp.numL2,
                   procdynp.numL2, procdynp.numL2, procdynp.numL2);
          l2.power = l2.power + l2array[i]->power * pppm_t;
          set_pppm(pppm_t, 1 / l2array[i]->cachep.executionTime, procdynp.numL2,
                   procdynp.numL2, procdynp.numL2);
          l2.rt_power = l2.rt_power + l2array[i]->rt_power * pppm_t;
          area.set_area(
              area.get_area() +
              l2.area.get_area());  // placement and routing overhead is 10%, l2
                                    // scales worse than cache 40% is
                                    // accumulated from 90 to 22nm
          power = power + l2.power;
          rt_power = rt_power + l2.rt_power;
        } else {
          l2.area.set_area(l2.area.get_area() + l2array[i]->area.get_area());
          area.set_area(
              area.get_area() +
              l2array[i]
                  ->area.get_area());  // placement and routing overhead is 10%,
                                       // l2 scales worse than cache 40% is
                                       // accumulated from 90 to 22nm

          set_pppm(pppm_t, l2array[i]->cachep.clockRate, 1, 1, 1);
          l2.power = l2.power + l2array[i]->power * pppm_t;
          power = power + l2array[i]->power * pppm_t;
          ;
          set_pppm(pppm_t, 1 / l2array[i]->cachep.executionTime, 1, 1, 1);
          l2.rt_power = l2.rt_power + l2array[i]->rt_power * pppm_t;
          rt_power = rt_power + l2array[i]->rt_power * pppm_t;
        }
      }
  }

  if (numL3 > 0)
    for (i = 0; i < numL3; i++) {
      l3array.push_back(new SharedCache(XML, i, &interface_ip, L3));
      l3array[i]->computeEnergy();
      l3array[i]->computeEnergy(false);
      if (procdynp.homoL3) {
        l3.area.set_area(l3.area.get_area() +
                         l3array[i]->area.get_area() * procdynp.numL3);
        set_pppm(pppm_t, l3array[i]->cachep.clockRate * procdynp.numL3,
                 procdynp.numL3, procdynp.numL3, procdynp.numL3);
        l3.power = l3.power + l3array[i]->power * pppm_t;
        set_pppm(pppm_t, 1 / l3array[i]->cachep.executionTime, procdynp.numL3,
                 procdynp.numL3, procdynp.numL3);
        l3.rt_power = l3.rt_power + l3array[i]->rt_power * pppm_t;
        area.set_area(
            area.get_area() +
            l3.area.get_area());  // placement and routing overhead is
                                  // 10%, l3 scales worse than cache
                                  // 40% is accumulated from 90 to 22nm
        power = power + l3.power;
        rt_power = rt_power + l3.rt_power;

      } else {
        l3.area.set_area(l3.area.get_area() + l3array[i]->area.get_area());
        area.set_area(
            area.get_area() +
            l3array[i]->area.get_area());  // placement and routing overhead is
                                           // 10%, l3 scales worse than cache
                                           // 40% is accumulated from 90 to 22nm
        set_pppm(pppm_t, l3array[i]->cachep.clockRate, 1, 1, 1);
        l3.power = l3.power + l3array[i]->power * pppm_t;
        power = power + l3array[i]->power * pppm_t;
        set_pppm(pppm_t, 1 / l3array[i]->cachep.executionTime, 1, 1, 1);
        l3.rt_power = l3.rt_power + l3array[i]->rt_power * pppm_t;
        rt_power = rt_power + l3array[i]->rt_power * pppm_t;
      }
    }
  if (numL1Dir > 0)
    for (i = 0; i < numL1Dir; i++) {
      l1dirarray.push_back(new SharedCache(XML, i, &interface_ip, L1Directory));
      l1dirarray[i]->computeEnergy();
      l1dirarray[i]->computeEnergy(false);
      if (procdynp.homoL1Dir) {
        l1dir.area.set_area(l1dir.area.get_area() +
                            l1dirarray[i]->area.get_area() * procdynp.numL1Dir);
        set_pppm(pppm_t, l1dirarray[i]->cachep.clockRate * procdynp.numL1Dir,
                 procdynp.numL1Dir, procdynp.numL1Dir, procdynp.numL1Dir);
        l1dir.power = l1dir.power + l1dirarray[i]->power * pppm_t;
        set_pppm(pppm_t, 1 / l1dirarray[i]->cachep.executionTime,
                 procdynp.numL1Dir, procdynp.numL1Dir, procdynp.numL1Dir);
        l1dir.rt_power = l1dir.rt_power + l1dirarray[i]->rt_power * pppm_t;
        area.set_area(
            area.get_area() +
            l1dir.area.get_area());  // placement and routing overhead is 10%,
                                     // l1dir scales worse than cache 40% is
                                     // accumulated from 90 to 22nm
        power = power + l1dir.power;
        rt_power = rt_power + l1dir.rt_power;

      } else {
        l1dir.area.set_area(l1dir.area.get_area() +
                            l1dirarray[i]->area.get_area());
        area.set_area(area.get_area() + l1dirarray[i]->area.get_area());
        set_pppm(pppm_t, l1dirarray[i]->cachep.clockRate, 1, 1, 1);
        l1dir.power = l1dir.power + l1dirarray[i]->power * pppm_t;
        power = power + l1dirarray[i]->power;
        set_pppm(pppm_t, 1 / l1dirarray[i]->cachep.executionTime, 1, 1, 1);
        l1dir.rt_power = l1dir.rt_power + l1dirarray[i]->rt_power * pppm_t;
        rt_power = rt_power + l1dirarray[i]->rt_power;
      }
    }

  if (numL2Dir > 0)
    for (i = 0; i < numL2Dir; i++) {
      l2dirarray.push_back(new SharedCache(XML, i, &interface_ip, L2Directory));
      l2dirarray[i]->computeEnergy();
      l2dirarray[i]->computeEnergy(false);
      if (procdynp.homoL2Dir) {
        l2dir.area.set_area(l2dir.area.get_area() +
                            l2dirarray[i]->area.get_area() * procdynp.numL2Dir);
        set_pppm(pppm_t, l2dirarray[i]->cachep.clockRate * procdynp.numL2Dir,
                 procdynp.numL2Dir, procdynp.numL2Dir, procdynp.numL2Dir);
        l2dir.power = l2dir.power + l2dirarray[i]->power * pppm_t;
        set_pppm(pppm_t, 1 / l2dirarray[i]->cachep.executionTime,
                 procdynp.numL2Dir, procdynp.numL2Dir, procdynp.numL2Dir);
        l2dir.rt_power = l2dir.rt_power + l2dirarray[i]->rt_power * pppm_t;
        area.set_area(
            area.get_area() +
            l2dir.area.get_area());  // placement and routing overhead is 10%,
                                     // l2dir scales worse than cache 40% is
                                     // accumulated from 90 to 22nm
        power = power + l2dir.power;
        rt_power = rt_power + l2dir.rt_power;

      } else {
        l2dir.area.set_area(l2dir.area.get_area() +
                            l2dirarray[i]->area.get_area());
        area.set_area(area.get_area() + l2dirarray[i]->area.get_area());
        set_pppm(pppm_t, l2dirarray[i]->cachep.clockRate, 1, 1, 1);
        l2dir.power = l2dir.power + l2dirarray[i]->power * pppm_t;
        power = power + l2dirarray[i]->power * pppm_t;
        set_pppm(pppm_t, 1 / l2dirarray[i]->cachep.executionTime, 1, 1, 1);
        l2dir.rt_power = l2dir.rt_power + l2dirarray[i]->rt_power * pppm_t;
        rt_power = rt_power + l2dirarray[i]->rt_power * pppm_t;
      }
    }

  if (XML->sys.mc.number_mcs > 0 && XML->sys.mc.memory_channels_per_mc > 0) {
    if (XML->sys.architecture == 1)  // 1 for fermi
      mc = new MemoryController(XML, &interface_ip, MC, GDDR5);
    else if (XML->sys.architecture == 2)  // 2 for quadro
      mc = new MemoryController(XML, &interface_ip, MC, GDDR3);
    else {
      printf("Architecture %d not defined!\n", XML->sys.architecture);
      printf("use 1 for fermi and 2 for quadro!\n");
      exit(1);
    }
    mc->computeEnergy();
    mc->computeEnergy(false);
    mcs.area.set_area(mcs.area.get_area() +
                      mc->area.get_area() * XML->sys.mc.number_mcs);
    area.set_area(area.get_area() +
                  mc->area.get_area() * XML->sys.mc.number_mcs);
    set_pppm(pppm_t, XML->sys.mc.number_mcs * mc->mcp.clockRate,
             XML->sys.mc.number_mcs, XML->sys.mc.number_mcs,
             XML->sys.mc.number_mcs);
    mcs.power = mc->power * pppm_t;
    power = power + mcs.power;
    set_pppm(pppm_t, 1 / mc->mcp.executionTime, XML->sys.mc.number_mcs,
             XML->sys.mc.number_mcs, XML->sys.mc.number_mcs);
    mcs.rt_power = mc->rt_power * pppm_t;
    rt_power = rt_power + mcs.rt_power;
  }

  if (XML->sys.flashc.number_mcs > 0)  // flash controller
  {
    flashcontroller = new FlashController(XML, &interface_ip);
    flashcontroller->computeEnergy();
    flashcontroller->computeEnergy(false);
    double number_fcs = flashcontroller->fcp.num_mcs;
    flashcontrollers.area.set_area(flashcontrollers.area.get_area() +
                                   flashcontroller->area.get_area() *
                                       number_fcs);
    area.set_area(area.get_area() + flashcontrollers.area.get_area());
    set_pppm(pppm_t, number_fcs, number_fcs, number_fcs, number_fcs);
    flashcontrollers.power = flashcontroller->power * pppm_t;
    power = power + flashcontrollers.power;
    set_pppm(pppm_t, number_fcs, number_fcs, number_fcs, number_fcs);
    flashcontrollers.rt_power = flashcontroller->rt_power * pppm_t;
    rt_power = rt_power + flashcontrollers.rt_power;
  }

  if (XML->sys.niu.number_units > 0) {
    niu = new NIUController(XML, &interface_ip);
    niu->computeEnergy();
    niu->computeEnergy(false);
    nius.area.set_area(nius.area.get_area() +
                       niu->area.get_area() * XML->sys.niu.number_units);
    area.set_area(area.get_area() +
                  niu->area.get_area() * XML->sys.niu.number_units);
    set_pppm(pppm_t, XML->sys.niu.number_units * niu->niup.clockRate,
             XML->sys.niu.number_units, XML->sys.niu.number_units,
             XML->sys.niu.number_units);
    nius.power = niu->power * pppm_t;
    power = power + nius.power;
    set_pppm(pppm_t, XML->sys.niu.number_units * niu->niup.clockRate,
             XML->sys.niu.number_units, XML->sys.niu.number_units,
             XML->sys.niu.number_units);
    nius.rt_power = niu->rt_power * pppm_t;
    rt_power = rt_power + nius.rt_power;
  }

  if (XML->sys.pcie.number_units > 0 && XML->sys.pcie.num_channels > 0) {
    pcie = new PCIeController(XML, &interface_ip);
    pcie->computeEnergy();
    pcie->computeEnergy(false);
    pcies.area.set_area(pcies.area.get_area() +
                        pcie->area.get_area() * XML->sys.pcie.number_units);
    area.set_area(area.get_area() +
                  pcie->area.get_area() * XML->sys.pcie.number_units);
    set_pppm(pppm_t, XML->sys.pcie.number_units * pcie->pciep.clockRate,
             XML->sys.pcie.number_units, XML->sys.pcie.number_units,
             XML->sys.pcie.number_units);
    pcies.power = pcie->power * pppm_t;
    power = power + pcies.power;
    set_pppm(pppm_t, XML->sys.pcie.number_units * pcie->pciep.clockRate,
             XML->sys.pcie.number_units, XML->sys.pcie.number_units,
             XML->sys.pcie.number_units);
    pcies.rt_power = pcie->rt_power * pppm_t;
    rt_power = rt_power + pcies.rt_power;
  }

  if (numNOC > 0) {
    for (i = 0; i < numNOC; i++) {
      if (XML->sys.NoC[i].type) {  // First add up area of routers if NoC is
                                   // used
        nocs.push_back(new NoC(XML, i, &interface_ip, 1));

        if (procdynp.homoNOC) {
          noc.area.set_area(noc.area.get_area() +
                            nocs[i]->area.get_area() * procdynp.numNOC);
          area.set_area(area.get_area() + noc.area.get_area());
        } else {
          noc.area.set_area(noc.area.get_area() + nocs[i]->area.get_area());
          area.set_area(area.get_area() + nocs[i]->area.get_area());
        }
      } else {  // Bus based interconnect
        nocs.push_back(
            new NoC(XML, i, &interface_ip, 1,
                    sqrt(area.get_area() * XML->sys.NoC[i].chip_coverage)));
        if (procdynp.homoNOC) {
          noc.area.set_area(noc.area.get_area() +
                            nocs[i]->area.get_area() * procdynp.numNOC);
          area.set_area(area.get_area() + noc.area.get_area());
        } else {
          noc.area.set_area(noc.area.get_area() + nocs[i]->area.get_area());
          area.set_area(area.get_area() + nocs[i]->area.get_area());
        }
      }
    }

    /*
     * Compute global links associated with each NOC, if any. This must be done
     * at the end (even after the NOC router part) since the total chip area
     * must be obtain to decide the link routing
     */
    for (i = 0; i < numNOC; i++) {
      if (nocs[i]->nocdynp.has_global_link && XML->sys.NoC[i].type) {
        nocs[i]->init_link_bus(
            sqrt(area.get_area() *
                 XML->sys.NoC[i].chip_coverage));  // compute global links
        if (procdynp.homoNOC) {
          noc.area.set_area(noc.area.get_area() +
                            nocs[i]->link_bus_tot_per_Router.area.get_area() *
                                nocs[i]->nocdynp.total_nodes * procdynp.numNOC);
          area.set_area(area.get_area() +
                        nocs[i]->link_bus_tot_per_Router.area.get_area() *
                            nocs[i]->nocdynp.total_nodes * procdynp.numNOC);
        } else {
          noc.area.set_area(noc.area.get_area() +
                            nocs[i]->link_bus_tot_per_Router.area.get_area() *
                                nocs[i]->nocdynp.total_nodes);
          area.set_area(area.get_area() +
                        nocs[i]->link_bus_tot_per_Router.area.get_area() *
                            nocs[i]->nocdynp.total_nodes);
        }
      }
    }
    // Compute energy of NoC (w or w/o links) or buses
    for (i = 0; i < numNOC; i++) {
      // cout<<"******************COMPUTE NOC ENERGY********************"<<endl;
      nocs[i]->computeEnergy();
      nocs[i]->computeEnergy(false);
      if (procdynp.homoNOC) {
        set_pppm(pppm_t, procdynp.numNOC * nocs[i]->nocdynp.clockRate,
                 procdynp.numNOC, procdynp.numNOC, procdynp.numNOC);
        noc.power = noc.power + nocs[i]->power * pppm_t;
        set_pppm(pppm_t, 1 / nocs[i]->nocdynp.executionTime, procdynp.numNOC,
                 procdynp.numNOC, procdynp.numNOC);
        noc.rt_power = noc.rt_power + nocs[i]->rt_power * pppm_t;
        power = power + noc.power;
        rt_power = rt_power + noc.rt_power;
      } else {
        set_pppm(pppm_t, nocs[i]->nocdynp.clockRate, 1, 1, 1);
        noc.power = noc.power + nocs[i]->power * pppm_t;
        power = power + nocs[i]->power * pppm_t;
        set_pppm(pppm_t, 1 / nocs[i]->nocdynp.executionTime, 1, 1, 1);
        noc.rt_power = noc.rt_power + nocs[i]->rt_power * pppm_t;
        rt_power = rt_power + nocs[i]->rt_power * pppm_t;
      }
    }
  }

  //  //clock power
  //  globalClock.init_wire_external(is_default, &interface_ip);
  //  globalClock.clk_area           =area*1e6; //change it from mm^2 to um^2
  //  globalClock.end_wiring_level   =5;//toplevel metal
  //  globalClock.start_wiring_level =5;//toplevel metal
  //  globalClock.l_ip.with_clock_grid=false;//global clock does not drive local
  //  final nodes globalClock.optimize_wire();
}

void Processor::compute() {
  int i;
  double pppm_t[4] = {1, 1, 1, 1};

  rt_power.reset();
  // power.reset();
  // core.power.reset();

  core.rt_power.reset();
  for (i = 0; i < numCore; i++) {
    cores[i]->executionTime =
        XML->sys.total_cycles / (XML->sys.core[i].clock_rate * 1e6);
    cores[i]->rt_power.reset();
    cores[i]->compute();
    // cores[i]->computeEnergy(false);
    if (procdynp.homoCore) {
      set_pppm(pppm_t, 1 / cores[i]->executionTime, procdynp.numCore,
               procdynp.numCore, procdynp.numCore);
      core.rt_power = core.rt_power + cores[i]->rt_power * pppm_t;
      rt_power = rt_power + core.rt_power;
    } else {
      set_pppm(pppm_t, 1 / cores[i]->executionTime, 1, 1, 1);
      core.rt_power = core.rt_power + cores[i]->rt_power * pppm_t;
      rt_power = rt_power + cores[i]->rt_power * pppm_t;
    }
  }

  if (!XML->sys.Private_L2) {
    if (numL2 > 0) l2.rt_power.reset();
    for (i = 0; i < numL2; i++) {
      l2array[i]->rt_power.reset();
      l2array[i]->cachep.executionTime =
          XML->sys.total_cycles / (XML->sys.core[0].clock_rate * 1e6);
      l2array[i]->computeEnergy(false);
      if (procdynp.homoL2) {
        set_pppm(pppm_t, 1 / l2array[i]->cachep.executionTime, procdynp.numL2,
                 procdynp.numL2, procdynp.numL2);
        l2.rt_power = l2.rt_power + l2array[i]->rt_power * pppm_t;
        rt_power = rt_power + l2.rt_power;
      } else {
        set_pppm(pppm_t, 1 / l2array[i]->cachep.executionTime, 1, 1, 1);
        l2.rt_power = l2.rt_power + l2array[i]->rt_power * pppm_t;
        rt_power = rt_power + l2array[i]->rt_power * pppm_t;
      }
    }
  }

  l3.rt_power.reset();
  if (numL3 > 0)
    for (i = 0; i < numL3; i++) {
      l3array[i]->rt_power.reset();
      l3array[i]->computeEnergy(false);
      if (procdynp.homoL3) {
        set_pppm(pppm_t, 1 / l3array[i]->cachep.executionTime, procdynp.numL3,
                 procdynp.numL3, procdynp.numL3);
        l3.rt_power = l3.rt_power + l3array[i]->rt_power * pppm_t;
        rt_power = rt_power + l3.rt_power;

      } else {
        set_pppm(pppm_t, 1 / l3array[i]->cachep.executionTime, 1, 1, 1);
        l3.rt_power = l3.rt_power + l3array[i]->rt_power * pppm_t;
        rt_power = rt_power + l3array[i]->rt_power * pppm_t;
      }
    }

  l1dir.rt_power.reset();
  if (numL1Dir > 0)
    for (i = 0; i < numL1Dir; i++) {
      l1dirarray[i]->rt_power.reset();
      l1dirarray[i]->computeEnergy(false);
      if (procdynp.homoL1Dir) {
        set_pppm(pppm_t, 1 / l1dirarray[i]->cachep.executionTime,
                 procdynp.numL1Dir, procdynp.numL1Dir, procdynp.numL1Dir);
        l1dir.rt_power = l1dir.rt_power + l1dirarray[i]->rt_power * pppm_t;
        rt_power = rt_power + l1dir.rt_power;

      } else {
        set_pppm(pppm_t, 1 / l1dirarray[i]->cachep.executionTime, 1, 1, 1);
        l1dir.rt_power = l1dir.rt_power + l1dirarray[i]->rt_power * pppm_t;
        rt_power = rt_power + l1dirarray[i]->rt_power;
      }
    }

  l2dir.rt_power.reset();
  if (numL2Dir > 0)
    for (i = 0; i < numL2Dir; i++) {
      l2dirarray[i]->rt_power.reset();
      l2dirarray[i]->computeEnergy(false);
      if (procdynp.homoL2Dir) {
        set_pppm(pppm_t, 1 / l2dirarray[i]->cachep.executionTime,
                 procdynp.numL2Dir, procdynp.numL2Dir, procdynp.numL2Dir);
        l2dir.rt_power = l2dir.rt_power + l2dirarray[i]->rt_power * pppm_t;
        rt_power = rt_power + l2dir.rt_power;

      } else {
        set_pppm(pppm_t, 1 / l2dirarray[i]->cachep.executionTime, 1, 1, 1);
        l2dir.rt_power = l2dir.rt_power + l2dirarray[i]->rt_power * pppm_t;
        rt_power = rt_power + l2dirarray[i]->rt_power * pppm_t;
      }
    }

  mcs.rt_power.reset();
  if (XML->sys.mc.number_mcs > 0 && XML->sys.mc.memory_channels_per_mc > 0) {
    mc->rt_power.reset();
    mc->mcp.executionTime =
        XML->sys.total_cycles / (XML->sys.core[0].clock_rate * 1e6);  // Jingwen
    mc->computeEnergy(false);
    set_pppm(pppm_t, 1 / mc->mcp.executionTime, XML->sys.mc.number_mcs,
             XML->sys.mc.number_mcs, XML->sys.mc.number_mcs);
    mcs.rt_power = mc->rt_power * pppm_t;
    rt_power = rt_power + mcs.rt_power;
  }

  /*
    if (XML->sys.flashc.number_mcs >0 )//flash controller
    {
            flashcontrollers.rt_power.reset();
            flashcontroller->computeEnergy(false);
            double number_fcs = flashcontroller->fcp.num_mcs;
            set_pppm(pppm_t,number_fcs , number_fcs ,number_fcs ,number_fcs );
            flashcontrollers.rt_power = flashcontroller->rt_power*pppm_t;
            rt_power = rt_power  + flashcontrollers.rt_power;

    }

    if (XML->sys.niu.number_units >0)
    {
            niu->computeEnergy(false);
            nius.rt_power.reset();
            set_pppm(pppm_t,XML->sys.niu.number_units*niu->niup.clockRate,
    XML->sys.niu.number_units,XML->sys.niu.number_units,XML->sys.niu.number_units);
            nius.rt_power = niu->rt_power*pppm_t;
            rt_power = rt_power  + nius.rt_power;

    }

    if (XML->sys.pcie.number_units >0 && XML->sys.pcie.num_channels >0)
    {
            pcie->computeEnergy(false);
            pcies.rt_power.reset();
            set_pppm(pppm_t,XML->sys.pcie.number_units*pcie->pciep.clockRate,
    XML->sys.pcie.number_units,XML->sys.pcie.number_units,XML->sys.pcie.number_units);
            pcies.rt_power = pcie->rt_power*pppm_t;
            rt_power = rt_power  + pcies.rt_power;

    }


             // * Compute global links associated with each NOC, if any. This
    must be done at the end (even after the NOC router part) since the total
    chip
             // * area must be obtain to decide the link routing
            */
  // Compute energy of NoC (w or w/o links) or buses
  noc.rt_power.reset();
  for (i = 0; i < numNOC; i++) {
    nocs[i]->nocdynp.executionTime =
        XML->sys.total_cycles / (XML->sys.core[0].clock_rate * 1e6);
    nocs[i]->computeEnergy(false);
    if (procdynp.homoNOC) {
      set_pppm(pppm_t, 1 / nocs[i]->nocdynp.executionTime, procdynp.numNOC,
               procdynp.numNOC, procdynp.numNOC);
      noc.rt_power = noc.rt_power + nocs[i]->rt_power * pppm_t;
      rt_power = rt_power + noc.rt_power;
    } else {
      set_pppm(pppm_t, 1 / nocs[i]->nocdynp.executionTime, 1, 1, 1);
      noc.rt_power = noc.rt_power + nocs[i]->rt_power * pppm_t;
      rt_power = rt_power + nocs[i]->rt_power * pppm_t;
    }
  }

  //  //clock power
  //  globalClock.init_wire_external(is_default, &interface_ip);
  //  globalClock.clk_area           =area*1e6; //change it from mm^2 to um^2
  //  globalClock.end_wiring_level   =5;//toplevel metal
  //  globalClock.start_wiring_level =5;//toplevel metal
  //  globalClock.l_ip.with_clock_grid=false;//global clock does not drive local
  //  final nodes globalClock.optimize_wire();
}

void Processor::displayDeviceType(int device_type_, uint32_t indent) {
  string indent_str(indent, ' ');

  switch (device_type_) {
    case 0:
      cout << indent_str << "Device Type= "
           << "ITRS high performance device type" << endl;
      break;
    case 1:
      cout << indent_str << "Device Type= "
           << "ITRS low standby power device type" << endl;
      break;
    case 2:
      cout << indent_str << "Device Type= "
           << "ITRS low operating power device type" << endl;
      break;
    case 3:
      cout << indent_str << "Device Type= "
           << "LP-DRAM device type" << endl;
      break;
    case 4:
      cout << indent_str << "Device Type= "
           << "COMM-DRAM device type" << endl;
      break;
    default: {
      cout << indent_str << "Unknown Device Type" << endl;
      exit(0);
    }
  }
}

void Processor::displayInterconnectType(int interconnect_type_,
                                        uint32_t indent) {
  string indent_str(indent, ' ');

  switch (interconnect_type_) {
    case 0:
      cout << indent_str << "Interconnect metal projection= "
           << "aggressive interconnect technology projection" << endl;
      break;
    case 1:
      cout << indent_str << "Interconnect metal projection= "
           << "conservative interconnect technology projection" << endl;
      break;
    default: {
      cout << indent_str << "Unknown Interconnect Projection Type" << endl;
      exit(0);
    }
  }
}

void Processor::displayEnergy(uint32_t indent, int plevel, bool is_tdp_parm) {
  int i;
  bool long_channel = XML->sys.longer_channel_device;
  string indent_str(indent, ' ');
  string indent_str_next(indent + 2, ' ');
  bool is_tdp = is_tdp_parm;
  if (is_tdp_parm) {
    if (plevel < 5) {
      cout
          << "\nMcPAT (version " << VER_MAJOR << "." << VER_MINOR << " of "
          << VER_UPDATE << ") results (current print level is " << plevel
          << ", please increase print level to see the details in components): "
          << endl;
    } else {
      cout << "\nMcPAT (version " << VER_MAJOR << "." << VER_MINOR << " of "
           << VER_UPDATE << ") results  (current print level is 5)" << endl;
    }
    cout << "******************************************************************"
            "***********************"
         << endl;
    cout << indent_str << "Technology " << XML->sys.core_tech_node << " nm"
         << endl;
    // cout <<indent_str<<"Device Type= "<<XML->sys.device_type<<endl;
    if (long_channel)
      cout << indent_str << "Using Long Channel Devices When Appropriate"
           << endl;
    // cout <<indent_str<<"Interconnect metal projection=
    // "<<XML->sys.interconnect_projection_type<<endl;
    displayInterconnectType(XML->sys.interconnect_projection_type, indent);
    cout << indent_str << "Core clock Rate(MHz) " << XML->sys.core[0].clock_rate
         << endl;
    cout << endl;
    cout << "******************************************************************"
            "***********************"
         << endl;
    cout << "Processor: " << endl;
    cout << indent_str << "Area = " << area.get_area() * 1e-6 << " mm^2"
         << endl;
    cout << indent_str << "Peak Power = "
         << power.readOp.dynamic +
                (long_channel ? power.readOp.longer_channel_leakage
                              : power.readOp.leakage) +
                power.readOp.gate_leakage
         << " W" << endl;
    cout << indent_str << "Total Leakage = "
         << (long_channel ? power.readOp.longer_channel_leakage
                          : power.readOp.leakage) +
                power.readOp.gate_leakage
         << " W" << endl;
    cout << indent_str << "Peak Dynamic = " << power.readOp.dynamic << " W"
         << endl;
    cout << indent_str << "Subthreshold Leakage = "
         << (long_channel ? power.readOp.longer_channel_leakage
                          : power.readOp.leakage)
         << " W" << endl;
    // cout << indent_str << "Subthreshold Leakage = " <<
    // power.readOp.longer_channel_leakage <<" W" << endl;
    cout << indent_str << "Gate Leakage = " << power.readOp.gate_leakage << " W"
         << endl;
    cout << indent_str << "Runtime Dynamic = " << rt_power.readOp.dynamic
         << " W" << endl;
    cout << endl;
    if (numCore > 0) {
      cout << indent_str << "Total Cores: " << XML->sys.number_of_cores
           << " cores " << endl;
      displayDeviceType(XML->sys.device_type, indent);
      cout << indent_str_next << "Area = " << core.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << core.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? core.power.readOp.longer_channel_leakage
                            : core.power.readOp.leakage)
           << " W" << endl;
      // cout << indent_str_next << "Subthreshold Leakage = " <<
      // core.power.readOp.longer_channel_leakage <<" W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << core.power.readOp.gate_leakage << " W"
           << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << core.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    if (!XML->sys.Private_L2) {
      if (numL2 > 0) {
        cout << indent_str << "Total L2s: " << endl;
        displayDeviceType(XML->sys.L2[0].device_type, indent);
        cout << indent_str_next << "Area = " << l2.area.get_area() * 1e-6
             << " mm^2" << endl;
        cout << indent_str_next << "Peak Dynamic = " << l2.power.readOp.dynamic
             << " W" << endl;
        cout << indent_str_next << "Subthreshold Leakage = "
             << (long_channel ? l2.power.readOp.longer_channel_leakage
                              : l2.power.readOp.leakage)
             << " W" << endl;
        // cout << indent_str_next << "Subthreshold Leakage = " <<
        // l2.power.readOp.longer_channel_leakage <<" W" << endl;
        cout << indent_str_next
             << "Gate Leakage = " << l2.power.readOp.gate_leakage << " W"
             << endl;
        cout << indent_str_next
             << "Runtime Dynamic = " << l2.rt_power.readOp.dynamic << " W"
             << endl;
        cout << endl;
      }
    }
    if (numL3 > 0) {
      cout << indent_str << "Total L3s: " << endl;
      displayDeviceType(XML->sys.L3[0].device_type, indent);
      cout << indent_str_next << "Area = " << l3.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << l3.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? l3.power.readOp.longer_channel_leakage
                            : l3.power.readOp.leakage)
           << " W" << endl;
      // cout << indent_str_next << "Subthreshold Leakage = " <<
      // l3.power.readOp.longer_channel_leakage <<" W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << l3.power.readOp.gate_leakage << " W" << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << l3.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    if (numL1Dir > 0) {
      cout << indent_str << "Total First Level Directory: " << endl;
      displayDeviceType(XML->sys.L1Directory[0].device_type, indent);
      cout << indent_str_next << "Area = " << l1dir.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << l1dir.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? l1dir.power.readOp.longer_channel_leakage
                            : l1dir.power.readOp.leakage)
           << " W" << endl;
      // cout << indent_str_next << "Subthreshold Leakage = " <<
      // l1dir.power.readOp.longer_channel_leakage <<" W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << l1dir.power.readOp.gate_leakage << " W"
           << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << l1dir.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    if (numL2Dir > 0) {
      cout << indent_str << "Total First Level Directory: " << endl;
      displayDeviceType(XML->sys.L1Directory[0].device_type, indent);
      cout << indent_str_next << "Area = " << l2dir.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << l2dir.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? l2dir.power.readOp.longer_channel_leakage
                            : l2dir.power.readOp.leakage)
           << " W" << endl;
      // cout << indent_str_next << "Subthreshold Leakage = " <<
      // l2dir.power.readOp.longer_channel_leakage <<" W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << l2dir.power.readOp.gate_leakage << " W"
           << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << l2dir.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    if (numNOC > 0) {
      cout << indent_str << "Total NoCs (Network/Bus): " << endl;
      displayDeviceType(XML->sys.device_type, indent);
      cout << indent_str_next << "Area = " << noc.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << noc.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? noc.power.readOp.longer_channel_leakage
                            : noc.power.readOp.leakage)
           << " W" << endl;
      // cout << indent_str_next << "Subthreshold Leakage = " <<
      // noc.power.readOp.longer_channel_leakage  <<" W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << noc.power.readOp.gate_leakage << " W"
           << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << noc.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    if (XML->sys.mc.number_mcs > 0 && XML->sys.mc.memory_channels_per_mc > 0) {
      cout << indent_str << "Total MCs: " << XML->sys.mc.number_mcs
           << " Memory Controllers " << endl;
      displayDeviceType(XML->sys.device_type, indent);
      cout << indent_str_next << "Area = " << mcs.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << mcs.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? mcs.power.readOp.longer_channel_leakage
                            : mcs.power.readOp.leakage)
           << " W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << mcs.power.readOp.gate_leakage << " W"
           << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << mcs.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    if (XML->sys.flashc.number_mcs > 0) {
      cout << indent_str
           << "Total Flash/SSD Controllers: " << flashcontroller->fcp.num_mcs
           << " Flash/SSD Controllers " << endl;
      displayDeviceType(XML->sys.device_type, indent);
      cout << indent_str_next
           << "Area = " << flashcontrollers.area.get_area() * 1e-6 << " mm^2"
           << endl;
      cout << indent_str_next
           << "Peak Dynamic = " << flashcontrollers.power.readOp.dynamic << " W"
           << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel
                   ? flashcontrollers.power.readOp.longer_channel_leakage
                   : flashcontrollers.power.readOp.leakage)
           << " W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << flashcontrollers.power.readOp.gate_leakage
           << " W" << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << flashcontrollers.rt_power.readOp.dynamic
           << " W" << endl;
      cout << endl;
    }
    if (XML->sys.niu.number_units > 0) {
      cout << indent_str << "Total NIUs: " << niu->niup.num_units
           << " Network Interface Units " << endl;
      displayDeviceType(XML->sys.device_type, indent);
      cout << indent_str_next << "Area = " << nius.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << nius.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? nius.power.readOp.longer_channel_leakage
                            : nius.power.readOp.leakage)
           << " W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << nius.power.readOp.gate_leakage << " W"
           << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << nius.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    if (XML->sys.pcie.number_units > 0 && XML->sys.pcie.num_channels > 0) {
      cout << indent_str << "Total PCIes: " << pcie->pciep.num_units
           << " PCIe Controllers " << endl;
      displayDeviceType(XML->sys.device_type, indent);
      cout << indent_str_next << "Area = " << pcies.area.get_area() * 1e-6
           << " mm^2" << endl;
      cout << indent_str_next << "Peak Dynamic = " << pcies.power.readOp.dynamic
           << " W" << endl;
      cout << indent_str_next << "Subthreshold Leakage = "
           << (long_channel ? pcies.power.readOp.longer_channel_leakage
                            : pcies.power.readOp.leakage)
           << " W" << endl;
      cout << indent_str_next
           << "Gate Leakage = " << pcies.power.readOp.gate_leakage << " W"
           << endl;
      cout << indent_str_next
           << "Runtime Dynamic = " << pcies.rt_power.readOp.dynamic << " W"
           << endl;
      cout << endl;
    }
    cout << "******************************************************************"
            "***********************"
         << endl;
    if (plevel > 1) {
      for (i = 0; i < numCore; i++) {
        cores[i]->displayEnergy(indent + 4, plevel, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
      if (!XML->sys.Private_L2) {
        for (i = 0; i < numL2; i++) {
          l2array[i]->displayEnergy(indent + 4, is_tdp);
          cout << "************************************************************"
                  "*****************************"
               << endl;
        }
      }
      for (i = 0; i < numL3; i++) {
        l3array[i]->displayEnergy(indent + 4, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
      for (i = 0; i < numL1Dir; i++) {
        l1dirarray[i]->displayEnergy(indent + 4, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
      for (i = 0; i < numL2Dir; i++) {
        l2dirarray[i]->displayEnergy(indent + 4, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
      if (XML->sys.mc.number_mcs > 0 &&
          XML->sys.mc.memory_channels_per_mc > 0) {
        mc->displayEnergy(indent + 4, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
      if (XML->sys.flashc.number_mcs > 0 &&
          XML->sys.flashc.memory_channels_per_mc > 0) {
        flashcontroller->displayEnergy(indent + 4, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
      if (XML->sys.niu.number_units > 0) {
        niu->displayEnergy(indent + 4, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
      if (XML->sys.pcie.number_units > 0 && XML->sys.pcie.num_channels > 0) {
        pcie->displayEnergy(indent + 4, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }

      for (i = 0; i < numNOC; i++) {
        nocs[i]->displayEnergy(indent + 4, plevel, is_tdp);
        cout << "**************************************************************"
                "***************************"
             << endl;
      }
    }
  } else {
  }
}

void Processor::set_proc_param() {
  bool debug = false;

  procdynp.homoCore = bool(debug ? 1 : XML->sys.homogeneous_cores);
  procdynp.homoL2 = bool(debug ? 1 : XML->sys.homogeneous_L2s);
  procdynp.homoL3 = bool(debug ? 1 : XML->sys.homogeneous_L3s);
  procdynp.homoNOC = bool(debug ? 1 : XML->sys.homogeneous_NoCs);
  procdynp.homoL1Dir = bool(debug ? 1 : XML->sys.homogeneous_L1Directories);
  procdynp.homoL2Dir = bool(debug ? 1 : XML->sys.homogeneous_L2Directories);

  procdynp.numCore = XML->sys.number_of_cores;
  procdynp.numL2 = XML->sys.number_of_L2s;
  procdynp.numL3 = XML->sys.number_of_L3s;
  procdynp.numNOC = XML->sys.number_of_NoCs;
  procdynp.numL1Dir = XML->sys.number_of_L1Directories;
  procdynp.numL2Dir = XML->sys.number_of_L2Directories;
  procdynp.numMC = XML->sys.mc.number_mcs;
  procdynp.numMCChannel = XML->sys.mc.memory_channels_per_mc;

  //	if (procdynp.numCore<1)
  //	{
  //		cout<<" The target processor should at least have one core on
  // chip."
  //<<endl; 		exit(0);
  //	}

  //  if (numNOCs<0 || numNOCs>2)
  //    {
  //  	  cout <<"number of NOCs must be 1 (only global NOCs) or 2 (both global
  //  and local NOCs)"<<endl; 	  exit(0);
  //    }

  /* Basic parameters*/
  interface_ip.data_arr_ram_cell_tech_type = debug ? 0 : XML->sys.device_type;
  interface_ip.data_arr_peri_global_tech_type =
      debug ? 0 : XML->sys.device_type;
  interface_ip.tag_arr_ram_cell_tech_type = debug ? 0 : XML->sys.device_type;
  interface_ip.tag_arr_peri_global_tech_type = debug ? 0 : XML->sys.device_type;

  interface_ip.ic_proj_type = debug ? 0 : XML->sys.interconnect_projection_type;
  interface_ip.delay_wt =
      100;                   // Fixed number, make sure timing can be satisfied.
  interface_ip.area_wt = 0;  // Fixed number, This is used to exhaustive search
                             // for individual components.
  interface_ip.dynamic_power_wt =
      100;  // Fixed number, This is used to exhaustive search for individual
            // components.
  interface_ip.leakage_power_wt = 0;
  interface_ip.cycle_time_wt = 0;

  interface_ip.delay_dev =
      10000;  // Fixed number, make sure timing can be satisfied.
  interface_ip.area_dev = 10000;  // Fixed number, This is used to exhaustive
                                  // search for individual components.
  interface_ip.dynamic_power_dev =
      10000;  // Fixed number, This is used to exhaustive search for individual
              // components.
  interface_ip.leakage_power_dev = 10000;
  interface_ip.cycle_time_dev = 10000;

  interface_ip.ed = 2;
  interface_ip.burst_len = 1;  // parameters are fixed for processor section,
                               // since memory is processed separately
  interface_ip.int_prefetch_w = 1;
  interface_ip.page_sz_bits = 0;
  interface_ip.temp = debug ? 360 : XML->sys.temperature;
  interface_ip.F_sz_nm =
      debug ? 90 : XML->sys.core_tech_node;  // XML->sys.core_tech_node;
  interface_ip.F_sz_um = interface_ip.F_sz_nm / 1000;

  //***********This section of code does not have real meaning, they are just to
  // ensure all data will have initial value to prevent errors. They will be
  // overridden  during each components initialization
  interface_ip.cache_sz = 64;
  interface_ip.line_sz = 1;
  interface_ip.assoc = 1;
  interface_ip.nbanks = 1;
  interface_ip.out_w = interface_ip.line_sz * 8;
  interface_ip.specific_tag = 1;
  interface_ip.tag_w = 64;
  interface_ip.access_mode = 2;

  interface_ip.obj_func_dyn_energy = 0;
  interface_ip.obj_func_dyn_power = 0;
  interface_ip.obj_func_leak_power = 0;
  interface_ip.obj_func_cycle_t = 1;

  interface_ip.is_main_mem = false;
  interface_ip.rpters_in_htree = true;
  interface_ip.ver_htree_wires_over_array = 0;
  interface_ip.broadcast_addr_din_over_ver_htrees = 0;

  interface_ip.num_rw_ports = 1;
  interface_ip.num_rd_ports = 0;
  interface_ip.num_wr_ports = 0;
  interface_ip.num_se_rd_ports = 0;
  interface_ip.num_search_ports = 1;
  interface_ip.nuca = 0;
  interface_ip.nuca_bank_count = 0;
  interface_ip.is_cache = true;
  interface_ip.pure_ram = false;
  interface_ip.pure_cam = false;
  interface_ip.force_cache_config = false;
  if (XML->sys.Embedded) {
    interface_ip.wt = Global_30;
    interface_ip.wire_is_mat_type = 0;
    interface_ip.wire_os_mat_type = 0;
  } else {
    interface_ip.wt = Global;
    interface_ip.wire_is_mat_type = 2;
    interface_ip.wire_os_mat_type = 2;
  }
  interface_ip.force_wiretype = false;
  interface_ip.print_detail = 1;
  interface_ip.add_ecc_b_ = true;
}

Processor::~Processor() {
  while (!cores.empty()) {
    delete cores.back();
    cores.pop_back();
  }
  while (!l2array.empty()) {
    delete l2array.back();
    l2array.pop_back();
  }
  while (!l3array.empty()) {
    delete l3array.back();
    l3array.pop_back();
  }
  while (!nocs.empty()) {
    delete nocs.back();
    nocs.pop_back();
  }
  if (!mc) {
    delete mc;
  }
  if (!niu) {
    delete niu;
  }
  if (!pcie) {
    delete pcie;
  }
  if (!flashcontroller) {
    delete flashcontroller;
  }
};
